/*!
 * ngCordova
 * v0.1.20-alpha
 * Copyright 2015 Drifty Co. http://drifty.com/
 * See LICENSE in this repository for license information
 */
(function(){

angular.module('ngCordova', [
  'ngCordova.plugins'
]);

// install   :     cordova plugin add https://github.com/whiteoctober/cordova-plugin-app-version.git
// link      :     https://github.com/whiteoctober/cordova-plugin-app-version

angular.module('ngCordova.plugins.appVersion', [])

  .factory('$cordovaAppVersion', ['$q', function ($q) {

    return {
      getVersionNumber: function () {
        var q = $q.defer();
        cordova.getAppVersion.getVersionNumber(function (version) {
          q.resolve(version);
        });

        return q.promise;
      },

      getVersionCode: function () {
        var q = $q.defer();
        cordova.getAppVersion.getVersionCode(function (code) {
          q.resolve(code);
        });

        return q.promise;
      }
    };
  }]);

// install  :     cordova plugin add https://github.com/katzer/cordova-plugin-badge.git
// link     :     https://github.com/katzer/cordova-plugin-badge

angular.module('ngCordova.plugins.badge', [])

  .factory('$cordovaBadge', ['$q', function ($q) {

    return {
      hasPermission: function () {
        var q = $q.defer();
        cordova.plugins.notification.badge.hasPermission(function (permission) {
          if (permission) {
            q.resolve(true);
          } else {
            q.reject('You do not have permission');
          }
        });

        return q.promise;
      },

      promptForPermission: function () {
        return cordova.plugins.notification.badge.promptForPermission();
      },

      set: function (badge, callback, scope) {
        var q = $q.defer();

        cordova.plugins.notification.badge.hasPermission(function (permission) {
          if (permission) {
            q.resolve(
              cordova.plugins.notification.badge.set(badge, callback, scope)
            );
          } else {
            q.reject('You do not have permission to set Badge');
          }
        });
        return q.promise;
      },

      get: function () {
        var q = $q.defer();
        cordova.plugins.notification.badge.hasPermission(function (permission) {
          if (permission) {
            cordova.plugins.notification.badge.get(function (badge) {
              q.resolve(badge);
            });
          } else {
            q.reject('You do not have permission to get Badge');
          }
        });

        return q.promise;
      },

      clear: function (callback, scope) {
        var q = $q.defer();

        cordova.plugins.notification.badge.hasPermission(function (permission) {
          if (permission) {
            q.resolve(cordova.plugins.notification.badge.clear(callback, scope));
          } else {
            q.reject('You do not have permission to clear Badge');
          }
        });
        return q.promise;
      },

      increase: function (count, callback, scope) {
        var q = $q.defer();

        this.hasPermission().then(function (){
          q.resolve(
            cordova.plugins.notification.badge.increase(count, callback, scope)
          );
        }, function (){
          q.reject('You do not have permission to increase Badge');
        }) ;

        return q.promise;
      },

      decrease: function (count, callback, scope) {
        var q = $q.defer();

        this.hasPermission().then(function (){
          q.resolve(
            cordova.plugins.notification.badge.decrease(count, callback, scope)
          );
        }, function (){
          q.reject('You do not have permission to decrease Badge');
        }) ;

        return q.promise;
      },

      configure: function (config) {
        return cordova.plugins.notification.badge.configure(config);
      }
    };
  }]);

// install  :    cordova plugin add https://github.com/wildabeast/BarcodeScanner.git
// link     :    https://github.com/wildabeast/BarcodeScanner

angular.module('ngCordova.plugins.barcodeScanner', [])

  .factory('$cordovaBarcodeScanner', ['$q', function ($q) {

    return {
      scan: function (config) {
        var q = $q.defer();

        cordova.plugins.barcodeScanner.scan(function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        }, config);

        return q.promise;
      },

      encode: function (type, data) {
        var q = $q.defer();
        type = type || 'TEXT_TYPE';

        cordova.plugins.barcodeScanner.encode(type, data, function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        });

        return q.promise;
      }
    };
  }]);

// install   :   cordova plugin add cordova-plugin-camera
// link      :   https://github.com/apache/cordova-plugin-camera

angular.module('ngCordova.plugins.camera', [])

  .factory('$cordovaCamera', ['$q', function ($q) {

    return {
      getPicture: function (options) {
        var q = $q.defer();

        if (!navigator.camera) {
          q.resolve(null);
          return q.promise;
        }

        navigator.camera.getPicture(function (imageData) {
          q.resolve(imageData);
        }, function (err) {
          q.reject(err);
        }, options);

        return q.promise;
      },

      cleanup: function () {
        var q = $q.defer();

        navigator.camera.cleanup(function () {
          q.resolve();
        }, function (err) {
          q.reject(err);
        });

        return q.promise;
      }
    };
  }]);

// install   :    cordova plugin add cordova-plugin-media-capture
// link      :    https://github.com/apache/cordova-plugin-media-capture

angular.module('ngCordova.plugins.capture', [])

  .factory('$cordovaCapture', ['$q', function ($q) {

    return {
      captureAudio: function (options) {
        var q = $q.defer();

        if (!navigator.device.capture) {
          q.resolve(null);
          return q.promise;
        }

        navigator.device.capture.captureAudio(function (audioData) {
          q.resolve(audioData);
        }, function (err) {
          q.reject(err);
        }, options);

        return q.promise;
      },
      captureImage: function (options) {
        var q = $q.defer();

        if (!navigator.device.capture) {
          q.resolve(null);
          return q.promise;
        }

        navigator.device.capture.captureImage(function (imageData) {
          q.resolve(imageData);
        }, function (err) {
          q.reject(err);
        }, options);

        return q.promise;
      },
      captureVideo: function (options) {
        var q = $q.defer();

        if (!navigator.device.capture) {
          q.resolve(null);
          return q.promise;
        }

        navigator.device.capture.captureVideo(function (videoData) {
          q.resolve(videoData);
        }, function (err) {
          q.reject(err);
        }, options);

        return q.promise;
      }
    };
  }]);

// install   :     cordova plugin add https://github.com/VersoSolutions/CordovaClipboard.git
// link      :     https://github.com/VersoSolutions/CordovaClipboard

angular.module('ngCordova.plugins.clipboard', [])

  .factory('$cordovaClipboard', ['$q', '$window', function ($q, $window) {

    return {
      copy: function (text) {
        var q = $q.defer();

        $window.cordova.plugins.clipboard.copy(text,
          function () {
            q.resolve();
          }, function () {
            q.reject();
          });

        return q.promise;
      },

      paste: function () {
        var q = $q.defer();

        $window.cordova.plugins.clipboard.paste(function (text) {
          q.resolve(text);
        }, function () {
          q.reject();
        });

        return q.promise;
      }
    };
  }]);

// install   :     cordova plugin add cordova-plugin-device
// link      :     https://github.com/apache/cordova-plugin-device

/* globals device: true */
angular.module('ngCordova.plugins.device', [])

  .factory('$cordovaDevice', [function () {

    return {
      /**
       * Returns the whole device object.
       * @see https://github.com/apache/cordova-plugin-device
       * @returns {Object} The device object.
       */
      getDevice: function () {
        return device;
      },

      /**
       * Returns the Cordova version.
       * @see https://github.com/apache/cordova-plugin-device#devicecordova
       * @returns {String} The Cordova version.
       */
      getCordova: function () {
        return device.cordova;
      },

      /**
       * Returns the name of the device's model or product.
       * @see https://github.com/apache/cordova-plugin-device#devicemodel
       * @returns {String} The name of the device's model or product.
       */
      getModel: function () {
        return device.model;
      },

      /**
       * @deprecated device.name is deprecated as of version 2.3.0. Use device.model instead.
       * @returns {String}
       */
      getName: function () {
        return device.name;
      },

      /**
       * Returns the device's operating system name.
       * @see https://github.com/apache/cordova-plugin-device#deviceplatform
       * @returns {String} The device's operating system name.
       */
      getPlatform: function () {
        return device.platform;
      },

      /**
       * Returns the device's Universally Unique Identifier.
       * @see https://github.com/apache/cordova-plugin-device#deviceuuid
       * @returns {String} The device's Universally Unique Identifier
       */
      getUUID: function () {
        return device.uuid;
      },

      /**
       * Returns the operating system version.
       * @see https://github.com/apache/cordova-plugin-device#deviceversion
       * @returns {String}
       */
      getVersion: function () {
        return device.version;
      },

      /**
       * Returns the device manufacturer.
       * @returns {String}
       */
      getManufacturer: function () {
        return device.manufacturer;
      }
    };
  }]);

// install   :     cordova plugin add cordova-plugin-geolocation
// link      :     https://github.com/apache/cordova-plugin-geolocation

angular.module('ngCordova.plugins.geolocation', [])

  .factory('$cordovaGeolocation', ['$q', function ($q) {

    return {
      getCurrentPosition: function (options) {
        var q = $q.defer();

        navigator.geolocation.getCurrentPosition(function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        }, options);

        return q.promise;
      },

      watchPosition: function (options) {
        var q = $q.defer();

        var watchID = navigator.geolocation.watchPosition(function (result) {
          q.notify(result);
        }, function (err) {
          q.reject(err);
        }, options);

        q.promise.cancel = function () {
          navigator.geolocation.clearWatch(watchID);
        };

        q.promise.clearWatch = function (id) {
          navigator.geolocation.clearWatch(id || watchID);
        };

        q.promise.watchID = watchID;

        return q.promise;
      },

      clearWatch: function (watchID) {
        return navigator.geolocation.clearWatch(watchID);
      }
    };
  }]);

// install  :     cordova plugin add https://github.com/wymsee/cordova-imagePicker.git
// link     :     https://github.com/wymsee/cordova-imagePicker

angular.module('ngCordova.plugins.imagePicker', [])

  .factory('$cordovaImagePicker', ['$q', '$window', function ($q, $window) {

    return {
      getPictures: function (options) {
        var q = $q.defer();

        $window.imagePicker.getPictures(function (results) {
          q.resolve(results);
        }, function (error) {
          q.reject(error);
        }, options);

        return q.promise;
      }
    };
  }]);

// install   :     cordova plugin add cordova-plugin-inappbrowser
// link      :     https://github.com/apache/cordova-plugin-inappbrowser

angular.module('ngCordova.plugins.inAppBrowser', [])

  .provider('$cordovaInAppBrowser', [function () {

    var ref;
    var defaultOptions = this.defaultOptions = {};

    this.setDefaultOptions = function (config) {
      defaultOptions = angular.extend(defaultOptions, config);
    };

    this.$get = ['$rootScope', '$q', '$window', '$timeout', function ($rootScope, $q, $window, $timeout) {
      return {
        open: function (url, target, requestOptions) {
          var q = $q.defer();

          if (requestOptions && !angular.isObject(requestOptions)) {
            q.reject('options must be an object');
            return q.promise;
          }

          var options = angular.extend({}, defaultOptions, requestOptions);

          var opt = [];
          angular.forEach(options, function (value, key) {
            opt.push(key + '=' + value);
          });
          var optionsString = opt.join();

          ref = $window.open(url, target, optionsString);

          ref.addEventListener('loadstart', function (event) {
            $timeout(function () {
              $rootScope.$broadcast('$cordovaInAppBrowser:loadstart', event);
            });
          }, false);

          ref.addEventListener('loadstop', function (event) {
            q.resolve(event);
            $timeout(function () {
              $rootScope.$broadcast('$cordovaInAppBrowser:loadstop', event);
            });
          }, false);

          ref.addEventListener('loaderror', function (event) {
            q.reject(event);
            $timeout(function () {
              $rootScope.$broadcast('$cordovaInAppBrowser:loaderror', event);
            });
          }, false);

          ref.addEventListener('exit', function (event) {
            $timeout(function () {
              $rootScope.$broadcast('$cordovaInAppBrowser:exit', event);
            });
          }, false);

          return q.promise;
        },

        close: function () {
          ref.close();
          ref = null;
        },

        show: function () {
          ref.show();
        },

        executeScript: function (details) {
          var q = $q.defer();

          ref.executeScript(details, function (result) {
            q.resolve(result);
          });

          return q.promise;
        },

        insertCSS: function (details) {
          var q = $q.defer();

          ref.insertCSS(details, function (result) {
            q.resolve(result);
          });

          return q.promise;
        }
      };
    }];
  }]);

// install  :     cordova plugin add https://github.com/EddyVerbruggen/Insomnia-PhoneGap-Plugin.git
// link     :     https://github.com/EddyVerbruggen/Insomnia-PhoneGap-Plugin
angular.module('ngCordova.plugins.insomnia', [])

  .factory('$cordovaInsomnia', ['$window', function ($window) {

    return {
      keepAwake: function () {
        return $window.plugins.insomnia.keepAwake();
      },
      allowSleepAgain: function () {
        return $window.plugins.insomnia.allowSleepAgain();
      }
    };

  }]);

// install   :   cordova plugins add https://github.com/vstirbu/InstagramPlugin.git
// link      :   https://github.com/vstirbu/InstagramPlugin

/* globals Instagram: true */
angular.module('ngCordova.plugins.instagram', [])

.factory('$cordovaInstagram', ['$q', function ($q) {

  return {
    share: function (options) {
      var q = $q.defer();

      if (!window.Instagram) {
        console.error('Tried to call Instagram.share but the Instagram plugin isn\'t installed!');
        q.resolve(null);
        return q.promise;
      }

      Instagram.share(options.image, options.caption, function (err) {
        if(err) {
          q.reject(err);
        } else {
          q.resolve(true);
        }
      });
      return q.promise;
    },
    isInstalled: function () {
      var q = $q.defer();

      if (!window.Instagram) {
        console.error('Tried to call Instagram.isInstalled but the Instagram plugin isn\'t installed!');
        q.resolve(null);
        return q.promise;
      }

      Instagram.isInstalled(function (err, installed) {
        if (err) {
          q.reject(err);
        } else {
          q.resolve(installed || true);
        }
      });
      return q.promise;
    }
  };
}]);

// install   :      cordova plugin add https://github.com/driftyco/ionic-plugins-keyboard.git
// link      :      https://github.com/driftyco/ionic-plugins-keyboard

angular.module('ngCordova.plugins.keyboard', [])

  .factory('$cordovaKeyboard', ['$rootScope', function ($rootScope) {

    var keyboardShowEvent = function () {
      $rootScope.$evalAsync(function () {
        $rootScope.$broadcast('$cordovaKeyboard:show');
      });
    };

    var keyboardHideEvent = function () {
      $rootScope.$evalAsync(function () {
        $rootScope.$broadcast('$cordovaKeyboard:hide');
      });
    };

    document.addEventListener('deviceready', function () {
      if (cordova.plugins.Keyboard) {
        window.addEventListener('native.keyboardshow', keyboardShowEvent, false);
        window.addEventListener('native.keyboardhide', keyboardHideEvent, false);
      }
    });

    return {
      hideAccessoryBar: function (bool) {
        return cordova.plugins.Keyboard.hideKeyboardAccessoryBar(bool);
      },

      close: function () {
        return cordova.plugins.Keyboard.close();
      },

      show: function () {
        return cordova.plugins.Keyboard.show();
      },

      disableScroll: function (bool) {
        return cordova.plugins.Keyboard.disableScroll(bool);
      },

      isVisible: function () {
        return cordova.plugins.Keyboard.isVisible;
      },

      clearShowWatch: function () {
        document.removeEventListener('native.keyboardshow', keyboardShowEvent);
        $rootScope.$$listeners['$cordovaKeyboard:show'] = [];
      },

      clearHideWatch: function () {
        document.removeEventListener('native.keyboardhide', keyboardHideEvent);
        $rootScope.$$listeners['$cordovaKeyboard:hide'] = [];
      }
    };
  }]);

// install   :  cordova plugin add https://github.com/katzer/cordova-plugin-local-notifications.git
// link      :  https://github.com/katzer/cordova-plugin-local-notifications

angular.module('ngCordova.plugins.localNotification', [])

  .factory('$cordovaLocalNotification', ['$q', '$window', '$rootScope', '$timeout', function ($q, $window, $rootScope, $timeout) {
    document.addEventListener('deviceready', function () {
      if ($window.cordova &&
        $window.cordova.plugins &&
        $window.cordova.plugins.notification &&
        $window.cordova.plugins.notification.local) {
        // ----- "Scheduling" events

        // A local notification was scheduled
        $window.cordova.plugins.notification.local.on('schedule', function (notification, state) {
          $timeout(function () {
            $rootScope.$broadcast('$cordovaLocalNotification:schedule', notification, state);
          });
        });

        // A local notification was triggered
        $window.cordova.plugins.notification.local.on('trigger', function (notification, state) {
          $timeout(function () {
            $rootScope.$broadcast('$cordovaLocalNotification:trigger', notification, state);
          });
        });

        // ----- "Update" events

        // A local notification was updated
        $window.cordova.plugins.notification.local.on('update', function (notification, state) {
          $timeout(function () {
            $rootScope.$broadcast('$cordovaLocalNotification:update', notification, state);
          });
        });

        // ----- "Clear" events

        // A local notification was cleared from the notification center
        $window.cordova.plugins.notification.local.on('clear', function (notification, state) {
          $timeout(function () {
            $rootScope.$broadcast('$cordovaLocalNotification:clear', notification, state);
          });
        });

        // All local notifications were cleared from the notification center
        $window.cordova.plugins.notification.local.on('clearall', function (state) {
          $timeout(function () {
            $rootScope.$broadcast('$cordovaLocalNotification:clearall', state);
          });
        });

        // ----- "Cancel" events

        // A local notification was cancelled
        $window.cordova.plugins.notification.local.on('cancel', function (notification, state) {
          $timeout(function () {
            $rootScope.$broadcast('$cordovaLocalNotification:cancel', notification, state);
          });
        });

        // All local notifications were cancelled
        $window.cordova.plugins.notification.local.on('cancelall', function (state) {
          $timeout(function () {
            $rootScope.$broadcast('$cordovaLocalNotification:cancelall', state);
          });
        });

        // ----- Other events

        // A local notification was clicked
        $window.cordova.plugins.notification.local.on('click', function (notification, state) {
          $timeout(function () {
            $rootScope.$broadcast('$cordovaLocalNotification:click', notification, state);
          });
        });
      }
    }, false);
    return {
      schedule: function (options, scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.schedule(options, function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      add: function (options, scope) {
        console.warn('Deprecated: use "schedule" instead.');

        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.schedule(options, function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      update: function (options, scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.update(options, function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      clear: function (ids, scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.clear(ids, function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      clearAll: function (scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.clearAll(function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      cancel: function (ids, scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.cancel(ids, function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      cancelAll: function (scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.cancelAll(function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      isPresent: function (id, scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.isPresent(id, function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      isScheduled: function (id, scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.isScheduled(id, function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      isTriggered: function (id, scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.isTriggered(id, function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      hasPermission: function (scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.hasPermission(function (result) {
          if (result) {
            q.resolve(result);
          } else {
            q.reject(result);
          }
        }, scope);

        return q.promise;
      },

      registerPermission: function (scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.registerPermission(function (result) {
          if (result) {
            q.resolve(result);
          } else {
            q.reject(result);
          }
        }, scope);

        return q.promise;
      },

      promptForPermission: function (scope) {
        console.warn('Deprecated: use "registerPermission" instead.');

        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.registerPermission(function (result) {
          if (result) {
            q.resolve(result);
          } else {
            q.reject(result);
          }
        }, scope);

        return q.promise;
      },

      getAllIds: function (scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.getAllIds(function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      getIds: function (scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.getIds(function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      getScheduledIds: function (scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.getScheduledIds(function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      getTriggeredIds: function (scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.getTriggeredIds(function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      get: function (ids, scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.get(ids, function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      getAll: function (scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.getAll(function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      getScheduled: function (ids, scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.getScheduled(ids, function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      getAllScheduled: function (scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.getAllScheduled(function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      getTriggered: function (ids, scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.getTriggered(ids, function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      getAllTriggered: function (scope) {
        var q = $q.defer();
        scope = scope || null;

        $window.cordova.plugins.notification.local.getAllTriggered(function (result) {
          q.resolve(result);
        }, scope);

        return q.promise;
      },

      getDefaults: function () {
        return $window.cordova.plugins.notification.local.getDefaults();
      },

      setDefaults: function (Object) {
        $window.cordova.plugins.notification.local.setDefaults(Object);
      }
    };
  }]);

// install  :     cordova plugin add https://github.com/floatinghotpot/cordova-plugin-mopub.git
// link     :     https://github.com/floatinghotpot/cordova-plugin-mopub

angular.module('ngCordova.plugins.mopubAds', [])
  .factory('$cordovaMoPubAds', ['$q', '$window', function ($q, $window) {

    return {
      setOptions: function (options) {
        var d = $q.defer();

        $window.MoPub.setOptions(options, function () {
          d.resolve();
        }, function () {
          d.reject();
        });

        return d.promise;
      },

      createBanner: function (options) {
        var d = $q.defer();

        $window.MoPub.createBanner(options, function () {
          d.resolve();
        }, function () {
          d.reject();
        });

        return d.promise;
      },

      removeBanner: function () {
        var d = $q.defer();

        $window.MoPub.removeBanner(function () {
          d.resolve();
        }, function () {
          d.reject();
        });

        return d.promise;
      },

      showBanner: function (position) {
        var d = $q.defer();

        $window.MoPub.showBanner(position, function () {
          d.resolve();
        }, function () {
          d.reject();
        });

        return d.promise;
      },

      showBannerAtXY: function (x, y) {
        var d = $q.defer();

        $window.MoPub.showBannerAtXY(x, y, function () {
          d.resolve();
        }, function () {
          d.reject();
        });

        return d.promise;
      },

      hideBanner: function () {
        var d = $q.defer();

        $window.MoPub.hideBanner(function () {
          d.resolve();
        }, function () {
          d.reject();
        });

        return d.promise;
      },

      prepareInterstitial: function (options) {
        var d = $q.defer();

        $window.MoPub.prepareInterstitial(options, function () {
          d.resolve();
        }, function () {
          d.reject();
        });

        return d.promise;
      },

      showInterstitial: function () {
        var d = $q.defer();

        $window.MoPub.showInterstitial(function () {
          d.resolve();
        }, function () {
          d.reject();
        });

        return d.promise;
      }
    };
  }]);

// install   :      cordova plugin add cordova-plugin-network-information
// link      :      https://github.com/apache/cordova-plugin-network-information

/* globals Connection: true */
angular.module('ngCordova.plugins.network', [])

  .factory('$cordovaNetwork', ['$rootScope', '$timeout', function ($rootScope, $timeout) {

    /**
      * Fires offline a event
      */
    var offlineEvent = function () {
      var networkState = navigator.connection.type;
      $timeout(function () {
        $rootScope.$broadcast('$cordovaNetwork:offline', networkState);
      });
    };

    /**
      * Fires online a event
      */
    var onlineEvent = function () {
      var networkState = navigator.connection.type;
      $timeout(function () {
        $rootScope.$broadcast('$cordovaNetwork:online', networkState);
      });
    };

    document.addEventListener('deviceready', function () {
      if (navigator.connection) {
        document.addEventListener('offline', offlineEvent, false);
        document.addEventListener('online', onlineEvent, false);
      }
    });

    return {
      getNetwork: function () {
        return navigator.connection.type;
      },

      isOnline: function () {
        var networkState = navigator.connection.type;
        return networkState !== Connection.UNKNOWN && networkState !== Connection.NONE;
      },

      isOffline: function () {
        var networkState = navigator.connection.type;
        return networkState === Connection.UNKNOWN || networkState === Connection.NONE;
      },

      clearOfflineWatch: function () {
        document.removeEventListener('offline', offlineEvent);
        $rootScope.$$listeners['$cordovaNetwork:offline'] = [];
      },

      clearOnlineWatch: function () {
        document.removeEventListener('online', onlineEvent);
        $rootScope.$$listeners['$cordovaNetwork:online'] = [];
      }
    };
  }])
  .run(['$injector', function ($injector) {
    $injector.get('$cordovaNetwork'); //ensure the factory always gets initialised
  }]);

// install   :      cordova plugin add https://github.com/phonegap-build/PushPlugin.git
// link      :      https://github.com/phonegap-build/PushPlugin

angular.module('ngCordova.plugins.push', [])

  .factory('$cordovaPush', ['$q', '$window', '$rootScope', '$timeout', function ($q, $window, $rootScope, $timeout) {

    return {
      onNotification: function (notification) {
        $timeout(function () {
          $rootScope.$broadcast('$cordovaPush:notificationReceived', notification);
        });
      },

      register: function (config) {
        var q = $q.defer();
        var injector;
        if (config !== undefined && config.ecb === undefined) {
          if (document.querySelector('[ng-app]') === null) {
            injector = 'document.body';
          }
          else {
            injector = 'document.querySelector(\'[ng-app]\')';
          }
          config.ecb = 'angular.element(' + injector + ').injector().get(\'$cordovaPush\').onNotification';
        }

        $window.plugins.pushNotification.register(function (token) {
          q.resolve(token);
        }, function (error) {
          q.reject(error);
        }, config);

        return q.promise;
      },

      unregister: function (options) {
        var q = $q.defer();
        $window.plugins.pushNotification.unregister(function (result) {
          q.resolve(result);
        }, function (error) {
          q.reject(error);
        }, options);

        return q.promise;
      },

      // iOS only
      setBadgeNumber: function (number) {
        var q = $q.defer();
        $window.plugins.pushNotification.setApplicationIconBadgeNumber(function (result) {
          q.resolve(result);
        }, function (error) {
          q.reject(error);
        }, number);
        return q.promise;
      }
    };
  }]);

// install   :      cordova plugin add https://github.com/cordova-sms/cordova-sms-plugin.git
// link      :      https://github.com/cordova-sms/cordova-sms-plugin

/* globals sms: true */
angular.module('ngCordova.plugins.sms', [])

  .factory('$cordovaSms', ['$q', function ($q) {

    return {
      send: function (number, message, options) {
        var q = $q.defer();
        sms.send(number, message, options, function (res) {
          q.resolve(res);
        }, function (err) {
          q.reject(err);
        });
        return q.promise;
      }
    };

  }]);

// install   :      cordova plugin add https://github.com/EddyVerbruggen/SocialSharing-PhoneGap-Plugin.git
// link      :      https://github.com/EddyVerbruggen/SocialSharing-PhoneGap-Plugin

// NOTE: shareViaEmail -> if user cancels sharing email, success is still called
// TODO: add support for iPad

angular.module('ngCordova.plugins.socialSharing', [])

  .factory('$cordovaSocialSharing', ['$q', '$window', function ($q, $window) {

    return {
      share: function (message, subject, file, link) {
        var q = $q.defer();
        subject = subject || null;
        file = file || null;
        link = link || null;
        $window.plugins.socialsharing.share(message, subject, file, link, function () {
          q.resolve(true);
        }, function () {
          q.reject(false);
        });
        return q.promise;
      },

      shareViaTwitter: function (message, file, link) {
        var q = $q.defer();
        file = file || null;
        link = link || null;
        $window.plugins.socialsharing.shareViaTwitter(message, file, link, function () {
          q.resolve(true);
        }, function () {
          q.reject(false);
        });
        return q.promise;
      },

      shareViaWhatsApp: function (message, file, link) {
        var q = $q.defer();
        file = file || null;
        link = link || null;
        $window.plugins.socialsharing.shareViaWhatsApp(message, file, link, function () {
          q.resolve(true);
        }, function () {
          q.reject(false);
        });
        return q.promise;
      },

      shareViaFacebook: function (message, file, link) {
        var q = $q.defer();
        message = message || null;
        file = file || null;
        link = link || null;
        $window.plugins.socialsharing.shareViaFacebook(message, file, link, function () {
          q.resolve(true);
        }, function () {
          q.reject(false);
        });
        return q.promise;
      },

      shareViaFacebookWithPasteMessageHint: function (message, file, link, pasteMessageHint) {
        var q = $q.defer();
        file = file || null;
        link = link || null;
        $window.plugins.socialsharing.shareViaFacebookWithPasteMessageHint(message, file, link, pasteMessageHint, function () {
          q.resolve(true);
        }, function () {
          q.reject(false);
        });
        return q.promise;
      },

      shareViaSMS: function (message, commaSeparatedPhoneNumbers) {
        var q = $q.defer();
        $window.plugins.socialsharing.shareViaSMS(message, commaSeparatedPhoneNumbers, function () {
          q.resolve(true);
        }, function () {
          q.reject(false);
        });
        return q.promise;
      },

      shareViaEmail: function (message, subject, toArr, ccArr, bccArr, fileArr) {
        var q = $q.defer();
        toArr = toArr || null;
        ccArr = ccArr || null;
        bccArr = bccArr || null;
        fileArr = fileArr || null;
        $window.plugins.socialsharing.shareViaEmail(message, subject, toArr, ccArr, bccArr, fileArr, function () {
          q.resolve(true);
        }, function () {
          q.reject(false);
        });
        return q.promise;
      },

      shareVia: function (via, message, subject, file, link) {
        var q = $q.defer();
        message = message || null;
        subject = subject || null;
        file = file || null;
        link = link || null;
        $window.plugins.socialsharing.shareVia(via, message, subject, file, link, function () {
          q.resolve(true);
        }, function () {
          q.reject(false);
        });
        return q.promise;
      },

      canShareViaEmail: function () {
        var q = $q.defer();
        $window.plugins.socialsharing.canShareViaEmail(function () {
          q.resolve(true);
        }, function () {
          q.reject(false);
        });
        return q.promise;
      },

      canShareVia: function (via, message, subject, file, link) {
        var q = $q.defer();
        $window.plugins.socialsharing.canShareVia(via, message, subject, file, link, function (success) {
          q.resolve(success);
        }, function (error) {
          q.reject(error);
        });
        return q.promise;
      },

      available: function () {
        var q = $q.defer();
        window.plugins.socialsharing.available(function (isAvailable) {
          if (isAvailable) {
            q.resolve();
          }
          else {
            q.reject();
          }
        });
      }
    };
  }]);

// install   :      cordova plugin add cordova-plugin-splashscreen
// link      :      https://github.com/apache/cordova-plugin-splashscreen

angular.module('ngCordova.plugins.splashscreen', [])

  .factory('$cordovaSplashscreen', [function () {

    return {
      hide: function () {
        return navigator.splashscreen.hide();
      },

      show: function () {
        return navigator.splashscreen.show();
      }
    };

  }]);

// install   :      cordova plugin add cordova-plugin-statusbar
// link      :      https://github.com/apache/cordova-plugin-statusbar

/* globals StatusBar: true */
angular.module('ngCordova.plugins.statusbar', [])

.factory('$cordovaStatusbar', [function () {

  return {

    /**
      * @param {boolean} bool
      */
    overlaysWebView: function (bool) {
      return StatusBar.overlaysWebView(!!bool);
    },

    STYLES: {
      DEFAULT: 0,
      LIGHT_CONTENT: 1,
      BLACK_TRANSLUCENT: 2,
      BLACK_OPAQUE: 3
    },

    /**
      * @param {number} style
      */
    style: function (style) {
      switch (style) {
        // Default
        case 0:
        return StatusBar.styleDefault();

        // LightContent
        case 1:
        return StatusBar.styleLightContent();

        // BlackTranslucent
        case 2:
        return StatusBar.styleBlackTranslucent();

        // BlackOpaque
        case 3:
        return StatusBar.styleBlackOpaque();

        default:
        return StatusBar.styleDefault();
      }
    },

    // supported names:
    // black, darkGray, lightGray, white, gray, red, green,
    // blue, cyan, yellow, magenta, orange, purple, brown
    styleColor: function (color) {
      return StatusBar.backgroundColorByName(color);
    },

    styleHex: function (colorHex) {
      return StatusBar.backgroundColorByHexString(colorHex);
    },

    hide: function () {
      return StatusBar.hide();
    },

    show: function () {
      return StatusBar.show();
    },

    isVisible: function () {
      return StatusBar.isVisible;
    }
  };
}]);

// install   :      cordova plugin add cordova-plugin-vibration
// link      :      https://github.com/apache/cordova-plugin-vibration

angular.module('ngCordova.plugins.vibration', [])

  .factory('$cordovaVibration', [function () {

    return {
      vibrate: function (times) {
        return navigator.notification.vibrate(times);
      },
      vibrateWithPattern: function (pattern, repeat) {
        return navigator.notification.vibrateWithPattern(pattern, repeat);
      },
      cancelVibration: function () {
        return navigator.notification.cancelVibration();
      }
    };
  }]);

// install   :    cordova plugin add https://github.com/EddyVerbruggen/VideoCapturePlus-PhoneGap-Plugin.git
// link      :    https://github.com/EddyVerbruggen/VideoCapturePlus-PhoneGap-Plugin

angular.module('ngCordova.plugins.videoCapturePlus', [])

  .provider('$cordovaVideoCapturePlus', [function () {

    var defaultOptions = {};


    /**
     * the nr of videos to record, default 1 (on iOS always 1)
     *
     * @param limit
     */
    this.setLimit = function setLimit(limit) {
      defaultOptions.limit = limit;
    };


    /**
     * max duration in seconds, default 0, which is 'forever'
     *
     * @param seconds
     */
    this.setMaxDuration = function setMaxDuration(seconds) {
      defaultOptions.duration = seconds;
    };


    /**
     * set to true to override the default low quality setting
     *
     * @param {Boolean} highquality
     */
    this.setHighQuality = function setHighQuality(highquality) {
      defaultOptions.highquality = highquality;
    };

    /**
     * you'll want to sniff the user-Agent/device and pass the best overlay based on that..
     * set to true to override the default backfacing camera setting. iOS: works fine, Android: YMMV (#18)
     *
     * @param {Boolean} frontcamera
     */
    this.useFrontCamera = function useFrontCamera(frontcamera) {
      defaultOptions.frontcamera = frontcamera;
    };


    /**
     * put the png in your www folder
     *
     * @param {String} imageUrl
     */
    this.setPortraitOverlay = function setPortraitOverlay(imageUrl) {
      defaultOptions.portraitOverlay = imageUrl;
    };


    /**
     *
     * @param {String} imageUrl
     */
    this.setLandscapeOverlay = function setLandscapeOverlay(imageUrl) {
      defaultOptions.landscapeOverlay = imageUrl;
    };


    /**
     * iOS only
     *
     * @param text
     */
    this.setOverlayText = function setOverlayText(text) {
      defaultOptions.overlayText = text;
    };


    this.$get = ['$q', '$window', function ($q, $window) {
      return {
        captureVideo: function (options) {
          var q = $q.defer();

          if (!$window.plugins.videocaptureplus) {
            q.resolve(null);
            return q.promise;
          }

          $window.plugins.videocaptureplus.captureVideo(q.resolve, q.reject,
            angular.extend({}, defaultOptions, options));

          return q.promise;
        }
      };
    }];
  }]);

//install   :     cordova plugin add cordova-plugin-file
//link      :     https://github.com/apache/cordova-plugin-file

angular.module('ngCordova.plugins.file', [])

.constant('$cordovaFileError', {
 1: 'NOT_FOUND_ERR',
 2: 'SECURITY_ERR',
 3: 'ABORT_ERR',
 4: 'NOT_READABLE_ERR',
 5: 'ENCODING_ERR',
 6: 'NO_MODIFICATION_ALLOWED_ERR',
 7: 'INVALID_STATE_ERR',
 8: 'SYNTAX_ERR',
 9: 'INVALID_MODIFICATION_ERR',
 10: 'QUOTA_EXCEEDED_ERR',
 11: 'TYPE_MISMATCH_ERR',
 12: 'PATH_EXISTS_ERR'
})

.provider('$cordovaFile', [function () {

 this.$get = ['$q', '$window', '$cordovaFileError', function ($q, $window, $cordovaFileError) {

   return {

     getFreeDiskSpace: function () {
       var q = $q.defer();
       cordova.exec(function (result) {
         q.resolve(result);
       }, function (error) {
         q.reject(error);
       }, 'File', 'getFreeDiskSpace', []);
       return q.promise;
     },

     checkDir: function (path, dir) {
       var q = $q.defer();

       if ((/^\//.test(dir))) {
         q.reject('directory cannot start with \/');
       }

       try {
         var directory = path + dir;
         $window.resolveLocalFileSystemURL(directory, function (fileSystem) {
           if (fileSystem.isDirectory === true) {
             q.resolve(fileSystem);
           } else {
             q.reject({code: 13, message: 'input is not a directory'});
           }
         }, function (error) {
           error.message = $cordovaFileError[error.code];
           q.reject(error);
         });
       } catch (err) {
         err.message = $cordovaFileError[err.code];
         q.reject(err);
       }

       return q.promise;
     },

     checkFile: function (path, file) {
       var q = $q.defer();

       if ((/^\//.test(file))) {
         q.reject('directory cannot start with \/');
       }

       try {
         var directory = path + file;
         $window.resolveLocalFileSystemURL(directory, function (fileSystem) {
           if (fileSystem.isFile === true) {
             q.resolve(fileSystem);
           } else {
             q.reject({code: 13, message: 'input is not a file'});
           }
         }, function (error) {
           error.message = $cordovaFileError[error.code];
           q.reject(error);
         });
       } catch (err) {
         err.message = $cordovaFileError[err.code];
         q.reject(err);
       }

       return q.promise;
     },

     createDir: function (path, dirName, replaceBool) {
       var q = $q.defer();

       if ((/^\//.test(dirName))) {
         q.reject('directory cannot start with \/');
       }

       replaceBool = replaceBool ? false : true;

       var options = {
         create: true,
         exclusive: replaceBool
       };

       try {
         $window.resolveLocalFileSystemURL(path, function (fileSystem) {
           fileSystem.getDirectory(dirName, options, function (result) {
             q.resolve(result);
           }, function (error) {
             error.message = $cordovaFileError[error.code];
             q.reject(error);
           });
         }, function (err) {
           err.message = $cordovaFileError[err.code];
           q.reject(err);
         });
       } catch (e) {
         e.message = $cordovaFileError[e.code];
         q.reject(e);
       }

       return q.promise;
     },

     createFile: function (path, fileName, replaceBool) {
       var q = $q.defer();

       if ((/^\//.test(fileName))) {
         q.reject('file-name cannot start with \/');
       }

       replaceBool = replaceBool ? false : true;

       var options = {
         create: true,
         exclusive: replaceBool
       };

       try {
         $window.resolveLocalFileSystemURL(path, function (fileSystem) {
           fileSystem.getFile(fileName, options, function (result) {
             q.resolve(result);
           }, function (error) {
             error.message = $cordovaFileError[error.code];
             q.reject(error);
           });
         }, function (err) {
           err.message = $cordovaFileError[err.code];
           q.reject(err);
         });
       } catch (e) {
         e.message = $cordovaFileError[e.code];
         q.reject(e);
       }
       return q.promise;
     },

     removeDir: function (path, dirName) {
       var q = $q.defer();

       if ((/^\//.test(dirName))) {
         q.reject('file-name cannot start with \/');
       }

       try {
         $window.resolveLocalFileSystemURL(path, function (fileSystem) {
           fileSystem.getDirectory(dirName, {create: false}, function (dirEntry) {
             dirEntry.remove(function () {
               q.resolve({success: true, fileRemoved: dirEntry});
             }, function (error) {
               error.message = $cordovaFileError[error.code];
               q.reject(error);
             });
           }, function (err) {
             err.message = $cordovaFileError[err.code];
             q.reject(err);
           });
         }, function (er) {
           er.message = $cordovaFileError[er.code];
           q.reject(er);
         });
       } catch (e) {
         e.message = $cordovaFileError[e.code];
         q.reject(e);
       }
       return q.promise;
     },

     removeFile: function (path, fileName) {
       var q = $q.defer();

       if ((/^\//.test(fileName))) {
         q.reject('file-name cannot start with \/');
       }

       try {
         $window.resolveLocalFileSystemURL(path, function (fileSystem) {
           fileSystem.getFile(fileName, {create: false}, function (fileEntry) {
             fileEntry.remove(function () {
               q.resolve({success: true, fileRemoved: fileEntry});
             }, function (error) {
               error.message = $cordovaFileError[error.code];
               q.reject(error);
             });
           }, function (err) {
             err.message = $cordovaFileError[err.code];
             q.reject(err);
           });
         }, function (er) {
           er.message = $cordovaFileError[er.code];
           q.reject(er);
         });
       } catch (e) {
         e.message = $cordovaFileError[e.code];
         q.reject(e);
       }
       return q.promise;
     },

     removeRecursively: function (path, dirName) {
       var q = $q.defer();

       if ((/^\//.test(dirName))) {
         q.reject('file-name cannot start with \/');
       }

       try {
         $window.resolveLocalFileSystemURL(path, function (fileSystem) {
           fileSystem.getDirectory(dirName, {create: false}, function (dirEntry) {
             dirEntry.removeRecursively(function () {
               q.resolve({success: true, fileRemoved: dirEntry});
             }, function (error) {
               error.message = $cordovaFileError[error.code];
               q.reject(error);
             });
           }, function (err) {
             err.message = $cordovaFileError[err.code];
             q.reject(err);
           });
         }, function (er) {
           er.message = $cordovaFileError[er.code];
           q.reject(er);
         });
       } catch (e) {
         e.message = $cordovaFileError[e.code];
         q.reject(e);
       }
       return q.promise;
     },

     writeFile: function (path, fileName, text, replaceBool) {
       var q = $q.defer();

       if ((/^\//.test(fileName))) {
         q.reject('file-name cannot start with \/');
       }

       replaceBool = replaceBool ? false : true;

       var options = {
         create: true,
         exclusive: replaceBool
       };

       try {
         $window.resolveLocalFileSystemURL(path, function (fileSystem) {
           fileSystem.getFile(fileName, options, function (fileEntry) {
             fileEntry.createWriter(function (writer) {
               if (options.append === true) {
                 writer.seek(writer.length);
               }

               if (options.truncate) {
                 writer.truncate(options.truncate);
               }

               writer.onwriteend = function (evt) {
                 if (this.error) {
                   q.reject(this.error);
                 } else {
                   q.resolve(evt);
                 }
               };

               writer.write(text);

               q.promise.abort = function () {
                 writer.abort();
               };
             });
           }, function (error) {
             error.message = $cordovaFileError[error.code];
             q.reject(error);
           });
         }, function (err) {
           err.message = $cordovaFileError[err.code];
           q.reject(err);
         });
       } catch (e) {
         e.message = $cordovaFileError[e.code];
         q.reject(e);
       }

       return q.promise;
     },

     writeExistingFile: function (path, fileName, text) {
       var q = $q.defer();

       if ((/^\//.test(fileName))) {
         q.reject('file-name cannot start with \/');
       }

       try {
         $window.resolveLocalFileSystemURL(path, function (fileSystem) {
           fileSystem.getFile(fileName, {create: false}, function (fileEntry) {
             fileEntry.createWriter(function (writer) {
               writer.seek(writer.length);

               writer.onwriteend = function (evt) {
                 if (this.error) {
                   q.reject(this.error);
                 } else {
                   q.resolve(evt);
                 }
               };

               writer.write(text);

               q.promise.abort = function () {
                 writer.abort();
               };
             });
           }, function (error) {
             error.message = $cordovaFileError[error.code];
             q.reject(error);
           });
         }, function (err) {
           err.message = $cordovaFileError[err.code];
           q.reject(err);
         });
       } catch (e) {
         e.message = $cordovaFileError[e.code];
         q.reject(e);
       }

       return q.promise;
     },

     readAsText: function (path, file) {
       var q = $q.defer();

       if ((/^\//.test(file))) {
         q.reject('file-name cannot start with \/');
       }

       try {
         $window.resolveLocalFileSystemURL(path, function (fileSystem) {
           fileSystem.getFile(file, {create: false}, function (fileEntry) {
             fileEntry.file(function (fileData) {
               var reader = new FileReader();

               reader.onloadend = function (evt) {
                 if (evt.target.result !== undefined || evt.target.result !== null) {
                   q.resolve(evt.target.result);
                 } else if (evt.target.error !== undefined || evt.target.error !== null) {
                   q.reject(evt.target.error);
                 } else {
                   q.reject({code: null, message: 'READER_ONLOADEND_ERR'});
                 }
               };

               reader.readAsText(fileData);
             });
           }, function (error) {
             error.message = $cordovaFileError[error.code];
             q.reject(error);
           });
         }, function (err) {
           err.message = $cordovaFileError[err.code];
           q.reject(err);
         });
       } catch (e) {
         e.message = $cordovaFileError[e.code];
         q.reject(e);
       }

       return q.promise;
     },

     readAsDataURL: function (path, file) {
       var q = $q.defer();

       if ((/^\//.test(file))) {
         q.reject('file-name cannot start with \/');
       }

       try {
         $window.resolveLocalFileSystemURL(path, function (fileSystem) {
           fileSystem.getFile(file, {create: false}, function (fileEntry) {
             fileEntry.file(function (fileData) {
               var reader = new FileReader();
               reader.onloadend = function (evt) {
                 if (evt.target.result !== undefined || evt.target.result !== null) {
                   q.resolve(evt.target.result);
                 } else if (evt.target.error !== undefined || evt.target.error !== null) {
                   q.reject(evt.target.error);
                 } else {
                   q.reject({code: null, message: 'READER_ONLOADEND_ERR'});
                 }
               };
               reader.readAsDataURL(fileData);
             });
           }, function (error) {
             error.message = $cordovaFileError[error.code];
             q.reject(error);
           });
         }, function (err) {
           err.message = $cordovaFileError[err.code];
           q.reject(err);
         });
       } catch (e) {
         e.message = $cordovaFileError[e.code];
         q.reject(e);
       }

       return q.promise;
     },

     readAsBinaryString: function (path, file) {
       var q = $q.defer();

       if ((/^\//.test(file))) {
         q.reject('file-name cannot start with \/');
       }

       try {
         $window.resolveLocalFileSystemURL(path, function (fileSystem) {
           fileSystem.getFile(file, {create: false}, function (fileEntry) {
             fileEntry.file(function (fileData) {
               var reader = new FileReader();
               reader.onloadend = function (evt) {
                 if (evt.target.result !== undefined || evt.target.result !== null) {
                   q.resolve(evt.target.result);
                 } else if (evt.target.error !== undefined || evt.target.error !== null) {
                   q.reject(evt.target.error);
                 } else {
                   q.reject({code: null, message: 'READER_ONLOADEND_ERR'});
                 }
               };
               reader.readAsBinaryString(fileData);
             });
           }, function (error) {
             error.message = $cordovaFileError[error.code];
             q.reject(error);
           });
         }, function (err) {
           err.message = $cordovaFileError[err.code];
           q.reject(err);
         });
       } catch (e) {
         e.message = $cordovaFileError[e.code];
         q.reject(e);
       }

       return q.promise;
     },

     readAsArrayBuffer: function (path, file) {
       var q = $q.defer();

       if ((/^\//.test(file))) {
         q.reject('file-name cannot start with \/');
       }

       try {
         $window.resolveLocalFileSystemURL(path, function (fileSystem) {
           fileSystem.getFile(file, {create: false}, function (fileEntry) {
             fileEntry.file(function (fileData) {
               var reader = new FileReader();
               reader.onloadend = function (evt) {
                 if (evt.target.result !== undefined || evt.target.result !== null) {
                   q.resolve(evt.target.result);
                 } else if (evt.target.error !== undefined || evt.target.error !== null) {
                   q.reject(evt.target.error);
                 } else {
                   q.reject({code: null, message: 'READER_ONLOADEND_ERR'});
                 }
               };
               reader.readAsArrayBuffer(fileData);
             });
           }, function (error) {
             error.message = $cordovaFileError[error.code];
             q.reject(error);
           });
         }, function (err) {
           err.message = $cordovaFileError[err.code];
           q.reject(err);
         });
       } catch (e) {
         e.message = $cordovaFileError[e.code];
         q.reject(e);
       }

       return q.promise;
     },

     moveFile: function (path, fileName, newPath, newFileName) {
       var q = $q.defer();

       newFileName = newFileName || fileName;

       if ((/^\//.test(fileName)) || (/^\//.test(newFileName))) {
         q.reject('file-name cannot start with \/');
       }

       try {
         $window.resolveLocalFileSystemURL(path, function (fileSystem) {
           fileSystem.getFile(fileName, {create: false}, function (fileEntry) {
             $window.resolveLocalFileSystemURL(newPath, function (newFileEntry) {
               fileEntry.moveTo(newFileEntry, newFileName, function (result) {
                 q.resolve(result);
               }, function (error) {
                 q.reject(error);
               });
             }, function (err) {
               q.reject(err);
             });
           }, function (err) {
             q.reject(err);
           });
         }, function (er) {
           q.reject(er);
         });
       } catch (e) {
         q.reject(e);
       }
       return q.promise;
     },

     moveDir: function (path, dirName, newPath, newDirName) {
       var q = $q.defer();

       newDirName = newDirName || dirName;

       if (/^\//.test(dirName) || (/^\//.test(newDirName))) {
         q.reject('file-name cannot start with \/');
       }

       try {
         $window.resolveLocalFileSystemURL(path, function (fileSystem) {
           fileSystem.getDirectory(dirName, {create: false}, function (dirEntry) {
             $window.resolveLocalFileSystemURL(newPath, function (newDirEntry) {
               dirEntry.moveTo(newDirEntry, newDirName, function (result) {
                 q.resolve(result);
               }, function (error) {
                 q.reject(error);
               });
             }, function (erro) {
               q.reject(erro);
             });
           }, function (err) {
             q.reject(err);
           });
         }, function (er) {
           q.reject(er);
         });
       } catch (e) {
         q.reject(e);
       }
       return q.promise;
     },

     copyDir: function (path, dirName, newPath, newDirName) {
       var q = $q.defer();

       newDirName = newDirName || dirName;

       if (/^\//.test(dirName) || (/^\//.test(newDirName))) {
         q.reject('file-name cannot start with \/');
       }

       try {
         $window.resolveLocalFileSystemURL(path, function (fileSystem) {
           fileSystem.getDirectory(dirName, {create: false, exclusive: false}, function (dirEntry) {

             $window.resolveLocalFileSystemURL(newPath, function (newDirEntry) {
               dirEntry.copyTo(newDirEntry, newDirName, function (result) {
                 q.resolve(result);
               }, function (error) {
                 error.message = $cordovaFileError[error.code];
                 q.reject(error);
               });
             }, function (erro) {
               erro.message = $cordovaFileError[erro.code];
               q.reject(erro);
             });
           }, function (err) {
             err.message = $cordovaFileError[err.code];
             q.reject(err);
           });
         }, function (er) {
           er.message = $cordovaFileError[er.code];
           q.reject(er);
         });
       } catch (e) {
         e.message = $cordovaFileError[e.code];
         q.reject(e);
       }
       return q.promise;
     },

     copyFile: function (path, fileName, newPath, newFileName) {
       var q = $q.defer();

       newFileName = newFileName || fileName;

       if ((/^\//.test(fileName))) {
         q.reject('file-name cannot start with \/');
       }

       try {
         $window.resolveLocalFileSystemURL(path, function (fileSystem) {
           fileSystem.getFile(fileName, {create: false, exclusive: false}, function (fileEntry) {

             $window.resolveLocalFileSystemURL(newPath, function (newFileEntry) {
               fileEntry.copyTo(newFileEntry, newFileName, function (result) {
                 q.resolve(result);
               }, function (error) {
                 error.message = $cordovaFileError[error.code];
                 q.reject(error);
               });
             }, function (erro) {
               erro.message = $cordovaFileError[erro.code];
               q.reject(erro);
             });
           }, function (err) {
             err.message = $cordovaFileError[err.code];
             q.reject(err);
           });
         }, function (er) {
           er.message = $cordovaFileError[er.code];
           q.reject(er);
         });
       } catch (e) {
         e.message = $cordovaFileError[e.code];
         q.reject(e);
       }
       return q.promise;
     }

     /*
      listFiles: function (path, dir) {

      },

      listDir: function (path, dirName) {
      var q = $q.defer();

      try {
      $window.resolveLocalFileSystemURL(path, function (fileSystem) {
      fileSystem.getDirectory(dirName, options, function (parent) {
      var reader = parent.createReader();
      reader.readEntries(function (entries) {
      q.resolve(entries);
      }, function () {
      q.reject('DIR_READ_ERROR : ' + path + dirName);
      });
      }, function (error) {
      error.message = $cordovaFileError[error.code];
      q.reject(error);
      });
      }, function (err) {
      err.message = $cordovaFileError[err.code];
      q.reject(err);
      });
      } catch (e) {
      e.message = $cordovaFileError[e.code];
      q.reject(e);
      }

      return q.promise;
      },

      readFileMetadata: function (filePath) {
      //return getFile(filePath, {create: false});
      }
      */
   };

 }];
}]);

//install   :      cordova plugin add https://github.com/pwlin/cordova-plugin-file-opener2.git
//link      :      https://github.com/pwlin/cordova-plugin-file-opener2

angular.module('ngCordova.plugins.fileOpener2', [])

.factory('$cordovaFileOpener2', ['$q', function ($q) {

 return {
   open: function (file, type) {
     var q = $q.defer();
     cordova.plugins.fileOpener2.open(file, type, {
       error: function (e) {
         q.reject(e);
       }, success: function () {
         q.resolve();
       }
     });
     return q.promise;
   },

   uninstall: function (pack) {
     var q = $q.defer();
     cordova.plugins.fileOpener2.uninstall(pack, {
       error: function (e) {
         q.reject(e);
       }, success: function () {
         q.resolve();
       }
     });
     return q.promise;
   },

   appIsInstalled: function (pack) {
     var q = $q.defer();
     cordova.plugins.fileOpener2.appIsInstalled(pack, {
       success: function (res) {
         q.resolve(res);
       }
     });
     return q.promise;
   }
 };
}]);

//install   :     cordova plugin add cordova-plugin-file-transfer
//link      :     https://github.com/apache/cordova-plugin-file-transfer

/* globals FileTransfer: true */
angular.module('ngCordova.plugins.fileTransfer', [])

.factory('$cordovaFileTransfer', ['$q', '$timeout', function ($q, $timeout) {
 return {
   download: function (source, filePath, options, trustAllHosts) {
     var q = $q.defer();
     var ft = new FileTransfer();
     var uri = (options && options.encodeURI === false) ? source : encodeURI(source);

     if (options && options.timeout !== undefined && options.timeout !== null) {
       $timeout(function () {
         ft.abort();
       }, options.timeout);
       options.timeout = null;
     }

     ft.onprogress = function (progress) {
       q.notify(progress);
     };

     q.promise.abort = function () {
       ft.abort();
     };

     ft.download(uri, filePath, q.resolve, q.reject, trustAllHosts, options);
     return q.promise;
   },

   upload: function (server, filePath, options, trustAllHosts) {
     var q = $q.defer();
     var ft = new FileTransfer();
     var uri = (options && options.encodeURI === false) ? server : encodeURI(server);

     if (options && options.timeout !== undefined && options.timeout !== null) {
       $timeout(function () {
         ft.abort();
       }, options.timeout);
       options.timeout = null;
     }

     ft.onprogress = function (progress) {
       q.notify(progress);
     };

     q.promise.abort = function () {
       ft.abort();
     };

     ft.upload(filePath, uri, q.resolve, q.reject, options, trustAllHosts);
     return q.promise;
   }
 };
}]);


//install   :      cordova plugin add https://github.com/pbernasconi/cordova-progressIndicator.git
//link      :      http://pbernasconi.github.io/cordova-progressIndicator/

/* globals ProgressIndicator: true */
angular.module('ngCordova.plugins.progressIndicator', [])

.factory('$cordovaProgress', [function () {

 return {
   show: function (_message) {
     var message = _message || 'Please wait...';
     return ProgressIndicator.show(message);
   },

   showSimple: function (_dim) {
     var dim = _dim || false;
     return ProgressIndicator.showSimple(dim);
   },

   showSimpleWithLabel: function (_dim, _label) {
     var dim = _dim || false;
     var label = _label || 'Loading...';
     return ProgressIndicator.showSimpleWithLabel(dim, label);
   },

   showSimpleWithLabelDetail: function (_dim, _label, _detail) {
     var dim = _dim || false;
     var label = _label || 'Loading...';
     var detail = _detail || 'Please wait';
     return ProgressIndicator.showSimpleWithLabelDetail(dim, label, detail);
   },

   showDeterminate: function (_dim, _timeout) {
     var dim = _dim || false;
     var timeout = _timeout || 50000;
     return ProgressIndicator.showDeterminate(dim, timeout);
   },

   showDeterminateWithLabel: function (_dim, _timeout, _label) {
     var dim = _dim || false;
     var timeout = _timeout || 50000;
     var label = _label || 'Loading...';

     return ProgressIndicator.showDeterminateWithLabel(dim, timeout, label);
   },

   showAnnular: function (_dim, _timeout) {
     var dim = _dim || false;
     var timeout = _timeout || 50000;
     return ProgressIndicator.showAnnular(dim, timeout);
   },

   showAnnularWithLabel: function (_dim, _timeout, _label) {
     var dim = _dim || false;
     var timeout = _timeout || 50000;
     var label = _label || 'Loading...';
     return ProgressIndicator.showAnnularWithLabel(dim, timeout, label);
   },

   showBar: function (_dim, _timeout) {
     var dim = _dim || false;
     var timeout = _timeout || 50000;
     return ProgressIndicator.showBar(dim, timeout);
   },

   showBarWithLabel: function (_dim, _timeout, _label) {
     var dim = _dim || false;
     var timeout = _timeout || 50000;
     var label = _label || 'Loading...';
     return ProgressIndicator.showBarWithLabel(dim, timeout, label);
   },

   showSuccess: function (_dim, _label) {
     var dim = _dim || false;
     var label = _label || 'Success';
     return ProgressIndicator.showSuccess(dim, label);
   },

   showText: function (_dim, _text, _position) {
     var dim = _dim || false;
     var text = _text || 'Warning';
     var position = _position || 'center';
     return ProgressIndicator.showText(dim, text, position);
   },

   hide: function () {
     return ProgressIndicator.hide();
   }
 };

}]);

//install   :      cordova plugin add https://github.com/EddyVerbruggen/Toast-PhoneGap-Plugin.git
//link      :      https://github.com/EddyVerbruggen/Toast-PhoneGap-Plugin

angular.module('ngCordova.plugins.toast', [])

.factory('$cordovaToast', ['$q', '$window', function ($q, $window) {

 return {
   showShortTop: function (message) {
     var q = $q.defer();
     $window.plugins.toast.showShortTop(message, function (response) {
       q.resolve(response);
     }, function (error) {
       q.reject(error);
     });
     return q.promise;
   },

   showShortCenter: function (message) {
     var q = $q.defer();
     $window.plugins.toast.showShortCenter(message, function (response) {
       q.resolve(response);
     }, function (error) {
       q.reject(error);
     });
     return q.promise;
   },

   showShortBottom: function (message) {
     var q = $q.defer();
     $window.plugins.toast.showShortBottom(message, function (response) {
       q.resolve(response);
     }, function (error) {
       q.reject(error);
     });
     return q.promise;
   },

   showLongTop: function (message) {
     var q = $q.defer();
     $window.plugins.toast.showLongTop(message, function (response) {
       q.resolve(response);
     }, function (error) {
       q.reject(error);
     });
     return q.promise;
   },

   showLongCenter: function (message) {
     var q = $q.defer();
     $window.plugins.toast.showLongCenter(message, function (response) {
       q.resolve(response);
     }, function (error) {
       q.reject(error);
     });
     return q.promise;
   },

   showLongBottom: function (message) {
     var q = $q.defer();
     $window.plugins.toast.showLongBottom(message, function (response) {
       q.resolve(response);
     }, function (error) {
       q.reject(error);
     });
     return q.promise;
   },


   show: function (message, duration, position) {
     var q = $q.defer();
     $window.plugins.toast.show(message, duration, position, function (response) {
       q.resolve(response);
     }, function (error) {
       q.reject(error);
     });
     return q.promise;
   }
 };

}]);

//install  :     cordova plugin add https://github.com/EddyVerbruggen/Calendar-PhoneGap-Plugin.git
//link     :     https://github.com/EddyVerbruggen/Calendar-PhoneGap-Plugin

angular.module('ngCordova.plugins.calendar', [])

.factory('$cordovaCalendar', ['$q', '$window', function ($q, $window) {
 
 return {
   createCalendar: function (options) {
     var d = $q.defer(),
       createCalOptions = $window.plugins.calendar.getCreateCalendarOptions();

     if (typeof options === 'string') {
       createCalOptions.calendarName = options;
     } else {
       createCalOptions = angular.extend(createCalOptions, options);
     }

     $window.plugins.calendar.createCalendar(createCalOptions, function (message) {
       d.resolve(message);
     }, function (error) {
       d.reject(error);
     });

     return d.promise;
   },

   deleteCalendar: function (calendarName) {
     var d = $q.defer();

     $window.plugins.calendar.deleteCalendar(calendarName, function (message) {
       d.resolve(message);
     }, function (error) {
       d.reject(error);
     });

     return d.promise;
   },

   createEvent: function (options) {
     var d = $q.defer(),
       defaultOptions = {
         title: null,
         location: null,
         notes: null,
         startDate: null,
         endDate: null
       };

     defaultOptions = angular.extend(defaultOptions, options);

     $window.plugins.calendar.createEvent(
       defaultOptions.title,
       defaultOptions.location,
       defaultOptions.notes,
       new Date(defaultOptions.startDate),
       new Date(defaultOptions.endDate),
       function (message) {
         d.resolve(message);
       }, function (error) {
         d.reject(error);
       }
     );

     return d.promise;
   },

   createEventWithOptions: function (options) {
     var d = $q.defer(),
       defaultOptionKeys = [],
       calOptions = window.plugins.calendar.getCalendarOptions(),
       defaultOptions = {
         title: null,
         location: null,
         notes: null,
         startDate: null,
         endDate: null
       };

     defaultOptionKeys = Object.keys(defaultOptions);

     for (var key in options) {
       if (defaultOptionKeys.indexOf(key) === -1) {
         calOptions[key] = options[key];
       } else {
         defaultOptions[key] = options[key];
       }
     }

     $window.plugins.calendar.createEventWithOptions(
       defaultOptions.title,
       defaultOptions.location,
       defaultOptions.notes,
       new Date(defaultOptions.startDate),
       new Date(defaultOptions.endDate),
       calOptions,
       function (message) {
         d.resolve(message);
       }, function (error) {
         d.reject(error);
       }
     );

     return d.promise;
   },

   createEventInteractively: function (options) {
     var d = $q.defer(),
       defaultOptions = {
         title: null,
         location: null,
         notes: null,
         startDate: null,
         endDate: null
       };

     defaultOptions = angular.extend(defaultOptions, options);

     $window.plugins.calendar.createEventInteractively(
       defaultOptions.title,
       defaultOptions.location,
       defaultOptions.notes,
       new Date(defaultOptions.startDate),
       new Date(defaultOptions.endDate),
       function (message) {
         d.resolve(message);
       }, function (error) {
         d.reject(error);
       }
     );

     return d.promise;
   },

   createEventInNamedCalendar: function (options) {
     var d = $q.defer(),
       defaultOptions = {
         title: null,
         location: null,
         notes: null,
         startDate: null,
         endDate: null,
         calendarName: null
       };

     defaultOptions = angular.extend(defaultOptions, options);

     $window.plugins.calendar.createEventInNamedCalendar(
       defaultOptions.title,
       defaultOptions.location,
       defaultOptions.notes,
       new Date(defaultOptions.startDate),
       new Date(defaultOptions.endDate),
       defaultOptions.calendarName,
       function (message) {
         d.resolve(message);
       }, function (error) {
         d.reject(error);
       }
     );

     return d.promise;
   },

   findEvent: function (options) {
     var d = $q.defer(),
       defaultOptions = {
         title: null,
         location: null,
         notes: null,
         startDate: null,
         endDate: null
       };

     defaultOptions = angular.extend(defaultOptions, options);

     $window.plugins.calendar.findEvent(
       defaultOptions.title,
       defaultOptions.location,
       defaultOptions.notes,
       new Date(defaultOptions.startDate),
       new Date(defaultOptions.endDate),
       function (foundEvent) {
         d.resolve(foundEvent);
       }, function (error) {
         d.reject(error);
       }
     );

     return d.promise;
   },

   listEventsInRange: function (startDate, endDate) {
     var d = $q.defer();

     $window.plugins.calendar.listEventsInRange(startDate, endDate, function (events) {
       d.resolve(events);
     }, function (error) {
       d.reject(error);
     });

     return d.promise;
   },

   listCalendars: function () {
     var d = $q.defer();

     $window.plugins.calendar.listCalendars(function (calendars) {
       d.resolve(calendars);
     }, function (error) {
       d.reject(error);
     });

     return d.promise;
   },

   findAllEventsInNamedCalendar: function (calendarName) {
     var d = $q.defer();

     $window.plugins.calendar.findAllEventsInNamedCalendar(calendarName, function (events) {
       d.resolve(events);
     }, function (error) {
       d.reject(error);
     });

     return d.promise;
   },

   modifyEvent: function (options) {
     var d = $q.defer(),
       defaultOptions = {
         title: null,
         location: null,
         notes: null,
         startDate: null,
         endDate: null,
         newTitle: null,
         newLocation: null,
         newNotes: null,
         newStartDate: null,
         newEndDate: null
       };

     defaultOptions = angular.extend(defaultOptions, options);

     $window.plugins.calendar.modifyEvent(
       defaultOptions.title,
       defaultOptions.location,
       defaultOptions.notes,
       new Date(defaultOptions.startDate),
       new Date(defaultOptions.endDate),
       defaultOptions.newTitle,
       defaultOptions.newLocation,
       defaultOptions.newNotes,
       new Date(defaultOptions.newStartDate),
       new Date(defaultOptions.newEndDate),
       function (message) {
         d.resolve(message);
       }, function (error) {
         d.reject(error);
       }
     );

     return d.promise;
   },

   deleteEvent: function (options) {
     var d = $q.defer(),
       defaultOptions = {
         newTitle: null,
         location: null,
         notes: null,
         startDate: null,
         endDate: null
       };

     defaultOptions = angular.extend(defaultOptions, options);

     $window.plugins.calendar.deleteEvent(
       defaultOptions.newTitle,
       defaultOptions.location,
       defaultOptions.notes,
       new Date(defaultOptions.startDate),
       new Date(defaultOptions.endDate),
       function (message) {
         d.resolve(message);
       }, function (error) {
         d.reject(error);
       }
     );

     return d.promise;
   }
 };
}]);


//install   :      cordova plugin add https://github.com/VitaliiBlagodir/cordova-plugin-datepicker.git
//link      :      https://github.com/VitaliiBlagodir/cordova-plugin-datepicker

angular.module('ngCordova.plugins.datePicker', [])

.factory('$cordovaDatePicker', ['$window', '$q', function ($window, $q) {
 
 return {
   show: function (options) {
     var q = $q.defer();
     options = options || {date: new Date(), mode: 'date'};
     $window.datePicker.show(options, function (date) {
       q.resolve(date);
     });
     return q.promise;
   }
 };
}]);

//install   :     cordova plugin add cordova-plugin-dialogs
//link      :     https://github.com/apache/cordova-plugin-dialogs

angular.module('ngCordova.plugins.dialogs', [])

.factory('$cordovaDialogs', ['$q', '$window', function ($q, $window) {

 return {
   alert: function (message, title, buttonName) {
     var q = $q.defer();

     if (!$window.navigator.notification) {
       $window.alert(message);
       q.resolve();
     } else {
       navigator.notification.alert(message, function () {
         q.resolve();
       }, title, buttonName);
     }

     return q.promise;
   },

   confirm: function (message, title, buttonLabels) {
     var q = $q.defer();

     if (!$window.navigator.notification) {
       if ($window.confirm(message)) {
         q.resolve(1);
       } else {
         q.resolve(2);
       }
     } else {
       navigator.notification.confirm(message, function (buttonIndex) {
         q.resolve(buttonIndex);
       }, title, buttonLabels);
     }

     return q.promise;
   },

   prompt: function (message, title, buttonLabels, defaultText) {
     var q = $q.defer();

     if (!$window.navigator.notification) {
       var res = $window.prompt(message, defaultText);
       if (res !== null) {
         q.resolve({input1: res, buttonIndex: 1});
       } else {
         q.resolve({input1: res, buttonIndex: 2});
       }
     } else {
       navigator.notification.prompt(message, function (result) {
         q.resolve(result);
       }, title, buttonLabels, defaultText);
     }
     return q.promise;
   },

   beep: function (times) {
     return navigator.notification.beep(times);
   }
 };
}]);


angular.module('ngCordova.plugins', [
  'ngCordova.plugins.appVersion',
  'ngCordova.plugins.barcodeScanner',
  'ngCordova.plugins.camera',
  'ngCordova.plugins.capture',
  'ngCordova.plugins.clipboard',
  'ngCordova.plugins.device',
  'ngCordova.plugins.geolocation',
  'ngCordova.plugins.imagePicker',
  'ngCordova.plugins.inAppBrowser',
  'ngCordova.plugins.localNotification',
  'ngCordova.plugins.network',
  'ngCordova.plugins.push',
  'ngCordova.plugins.sms',
  'ngCordova.plugins.socialSharing',
  'ngCordova.plugins.splashscreen',
  'ngCordova.plugins.statusbar',
  'ngCordova.plugins.vibration',
  'ngCordova.plugins.videoCapturePlus',
  'ngCordova.plugins.file',
  'ngCordova.plugins.fileTransfer',
  'ngCordova.plugins.fileOpener2',
  'ngCordova.plugins.progressIndicator',
  'ngCordova.plugins.toast',
  'ngCordova.plugins.datePicker',
  'ngCordova.plugins.calendar',
  'ngCordova.plugins.dialogs',
  'ngCordova.plugins.keyboard',
]);
})();